from interface.widget import Page, scale, PagePort
from tkinter import ttk
from utils import memory
from utils.bank import bank_algorithm


def list2dict(lis):
    dic = {idx: lis[idx] for idx in range(len(lis))}
    return dic


def dict2list(dic):
    keys = list(dic.keys())
    keys.sort()
    lis = [dic[key] for key in keys]
    return lis


def text2int_list(text):
    return [int(x) for x in text.split(',')]


class BankerPage(Page):

    def __init__(self, master):
        Page.__init__(self, master)
        self.page_port = None

    def content(self, master):
        memory.app.tk.title('银行家算法')

        page_port = PagePort(master)
        page_port.relx = 0
        page_port.rely = 0
        page_port.relwidth = 1
        page_port.relheight = 1
        page_port.display()
        page_port.open_page(BankerPageInputProgressName(page_port))

        self.page_port = page_port


class BankerPageInputProgressName(Page):

    def content(self, master):
        title_label = ttk.Label(master, text='请输入进程名，中间用英文逗号隔开')
        title_label.place(**scale(x=30, y=20, relwidth=1, width=-130, height=40))

        progress_entry = ttk.Entry(master)
        progress_entry.place(**scale(x=30, y=60, relwidth=1, width=-60, height=30))

        def next_button_method():
            text = progress_entry.get()
            progress_names = [p.lstrip(' ').rstrip(' ') for p in text.split(',')]
            self.master.close_page()
            self.master.open_page(BankerPageInputResource(self.master, progress_names))

        next_button = ttk.Button(master, text='下一步', command=next_button_method)
        next_button.place(**scale(relx=1, x=-100, y=25, width=70, height=30))


class BankerPageInputResource(Page):

    def __init__(self, master, progress_names):
        Page.__init__(self, master)
        self.progress_names = progress_names

    def content(self, master):
        progress_names = self.progress_names

        ava_res_label = ttk.Label(master, text='请输入当前可用资源数，中间用逗号隔开')
        ava_res_label.place(**scale(x=30, y=20, relwidth=1, width=-130, height=40))
        ava_res_entry = ttk.Entry(master)
        ava_res_entry.place(**scale(x=30, y=60, relwidth=1, width=-60, height=30))

        table = ttk.Frame(master)
        table.place(**scale(x=30, y=100, relwidth=1, width=-60, relheight=1, height=-130))

        grid_widgets = []
        first_line_widgets = []
        label1 = ttk.Label(table, text='进程')
        label1.place(**scale(relx=0, y=40 * len(grid_widgets), relwidth=0.2, height=30))
        first_line_widgets.append(label1)
        label2 = ttk.Label(table, text='已分配的资源')
        label2.place(**scale(relx=0.2, y=40 * len(grid_widgets), relwidth=0.4, height=30))
        first_line_widgets.append(label2)
        label3 = ttk.Label(table, text='尚需分配的资源')
        label3.place(**scale(relx=0.6, y=40 * len(grid_widgets), relwidth=0.4, height=30))
        first_line_widgets.append(label3)
        grid_widgets.append(first_line_widgets)
        for name in progress_names:
            line_widgets = []
            label1 = ttk.Label(table, text=name)
            label1.place(**scale(relx=0, y=40 * len(grid_widgets), relwidth=0.2, height=30))
            line_widgets.append(label1)
            entry2 = ttk.Entry(table)
            entry2.place(**scale(relx=0.2, y=40 * len(grid_widgets), relwidth=0.4, width=-10, height=30))
            line_widgets.append(entry2)
            entry3 = ttk.Entry(table)
            entry3.place(**scale(relx=0.6, y=40 * len(grid_widgets), relwidth=0.4, width=-10, height=30))
            line_widgets.append(entry3)
            grid_widgets.append(line_widgets)

        def next_button_method():
            system = {
                'res_available': list2dict(text2int_list(ava_res_entry.get())),
                'progress': [{
                    'name': line[0]['text'],
                    'res_has': list2dict(text2int_list(line[1].get())),
                    'res_need': list2dict(text2int_list(line[2].get())),
                    'is_stop': False
                } for line in grid_widgets[1:]],
                'select': ''
            }
            self.master.close_page()
            self.master.open_page(BankPageSolution(self.master, progress_names, system))

        next_button = ttk.Button(master, text='下一步', command=next_button_method)
        next_button.place(**scale(relx=1, x=-100, y=25, width=70, height=30))


class BankPageSolution(Page):

    def __init__(self, master, progress_names, system_init):
        Page.__init__(self, master)
        self.progress_names = progress_names
        self.system_init = system_init

    def content(self, master):
        solution = bank_algorithm(self.system_init)
        solution_step_idx = 0

        progress_names = self.progress_names

        tick_label = ttk.Label(master, text='周期数')
        tick_label.place(**scale(x=30, y=20, width=150, height=25))
        tick_value = ttk.Label(master, text=0)
        tick_value.place(**scale(x=180, y=20, width=150, height=25))
        res_label = ttk.Label(master, text='当前可用资源数')
        res_label.place(**scale(x=30, y=45, width=150, height=25))
        res_value = ttk.Label(master, text='[]')
        res_value.place(**scale(x=180, y=45, width=150, height=25))
        dead_label = ttk.Label(master, text='是否会发生死锁')
        dead_label.place(**scale(x=30, y=70, width=150, height=25))
        dead_value = ttk.Label(master)
        dead_value.place(**scale(x=180, y=70, width=150, height=25))

        if solution['is_deadlock']:
            dead_value['text'] = '在第{}个周期发生死锁'.format(len(solution['step']) - 1)
        else:
            dead_value['text'] = '否'

        table = ttk.Frame(master)
        table.place(**scale(x=30, y=100, relwidth=1, width=-60, relheight=1, height=-130))

        grid_widgets = []
        first_line_widgets = []
        label1 = ttk.Label(table, text='进程')
        label1.place(**scale(relx=0, y=40 * len(grid_widgets), relwidth=0.2, height=30))
        first_line_widgets.append(label1)
        label2 = ttk.Label(table, text='已分配的资源')
        label2.place(**scale(relx=0.2, y=40 * len(grid_widgets), relwidth=0.4, height=30))
        first_line_widgets.append(label2)
        label3 = ttk.Label(table, text='尚需分配的资源')
        label3.place(**scale(relx=0.6, y=40 * len(grid_widgets), relwidth=0.4, height=30))
        first_line_widgets.append(label3)
        grid_widgets.append(first_line_widgets)
        for name in progress_names:
            line_widgets = []
            label1 = ttk.Label(table, text=name)
            label1.place(**scale(relx=0, y=40 * len(grid_widgets), relwidth=0.2, height=30))
            line_widgets.append(label1)
            entry2 = ttk.Label(table)
            entry2.place(**scale(relx=0.2, y=40 * len(grid_widgets), relwidth=0.4, width=-10, height=30))
            line_widgets.append(entry2)
            entry3 = ttk.Label(table)
            entry3.place(**scale(relx=0.6, y=40 * len(grid_widgets), relwidth=0.4, width=-10, height=30))
            line_widgets.append(entry3)
            grid_widgets.append(line_widgets)

        def show_step():
            tick_value['text'] = solution_step_idx
            res_value['text'] = str(dict2list(solution['step'][solution_step_idx]['res_available']))
            progress = solution['step'][solution_step_idx]['progress']
            select_name = solution['step'][solution_step_idx]['select']
            for idx in range(len(progress)):
                line = grid_widgets[idx+1]
                line[0]['text'] = progress[idx]['name']
                line[1]['text'] = str(dict2list(progress[idx]['res_has']))
                line[2]['text'] = str(dict2list(progress[idx]['res_need']))
                if progress[idx]['name'] == select_name:
                    line[0]['text'] += '   <--'
                if progress[idx]['is_stop']:
                    line[0]['text'] += ' (Finished)'

        show_step()

        def previous_button_method():
            nonlocal solution_step_idx
            if solution_step_idx > 0:
                solution_step_idx -= 1
            show_step()

        previous_button = ttk.Button(master, text='上一步', command=previous_button_method)
        previous_button.place(**scale(relx=1, x=-180, y=25, width=70, height=30))

        def next_button_method():
            nonlocal solution_step_idx
            if solution_step_idx < len(solution['step']) - 1:
                solution_step_idx += 1
            show_step()

        next_button = ttk.Button(master, text='下一步', command=next_button_method)
        next_button.place(**scale(relx=1, x=-100, y=25, width=70, height=30))
